package org.example.day11;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 4.1.7:实现 生产者/消费者 交替打印
 * 优化:只用一个condition有可能唤醒自己线程的等待，重复判断又进入wait.可以使用两个ConditionA和ConditionB来达到只唤醒对方线程.
 */
public class MyThread {
    private ReentrantLock lock = new ReentrantLock();
    private Condition conditionA = lock.newCondition();
    private Condition conditionB = lock.newCondition();
    //检测打印次数
    int countA = 1;
    int countB = 1;
    //检测进入while判断的次数
    int accessA = 1;
    int accessB = 1;
    private boolean hasValue = false;
    public void set(){
        try {
            lock.lock();
            while(hasValue == true){
                System.out.println("accessA" + accessA++);
                conditionA.await();
            }
            System.out.println("打印★" + (countA++));
            hasValue = true;
            conditionB.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public void get(){
        try {
            lock.lock();
            while(hasValue == false){
                System.out.println("accessB" + accessB++);
                conditionB.await();
            }
            System.out.println("打印☆" + (countB++));
            hasValue = false;
            conditionA.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        long startTime = System.currentTimeMillis();
        MyThread m1 = new MyThread();
        Thread1A ta = new Thread1A(m1);
        ta.start();
        Thread1B tb = new Thread1B(m1);
        tb.start();
        ta.join();
        tb.join();
        long endTime = System.currentTimeMillis();
        System.out.println("用时: " + (endTime - startTime));
    }
}

class Thread1A extends Thread{
    private MyThread m1;

    public Thread1A(MyThread m1) {
        this.m1 = m1;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10000; i++) {
            m1.set();
        }
    }
}

class Thread1B extends Thread{
    private MyThread m1;

    public Thread1B(MyThread m1) {
        this.m1 = m1;
    }

    @Override
    public void run() {
        for (int i = 0; i <10000; i++) {
            m1.get();
        }
    }
}